﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using OhioState.Graphics.OpenGL;
using OhioState.Graphics;
using OhioState.Graphics.Proxy;
using OhioState.Controls;
using OhioState.AssetManaged;
using OhioState.Math;
using System.Configuration;
using OhioState.Controls.GLSL;
using System.Runtime.Remoting;

namespace GL_Panel
{
    /// <summary>
    /// Simple example of using remoting within the framework.
    /// A GL panel is created in a form, it gets all the necessary assets
    /// from the remoted AssetManager (object reference is obtained
    /// via .net remoting) Multiple clients can be connected to a
    /// single TestForm.
    /// </summary>
    public partial class GL_Form : Form
    {
        private static String address = "tcp://localhost:8007/";

        private ExaminerMouseHandler examiner;
        private ICamera camera;
        private ViewProxy viewProxy;
        private ViewHandler viewHandler;
        private AssetManagerGL openGLAssetManager;
        private IAssetManagedHandler eventHandler;
        private ConnectForm connectForm;
        private AssetManager assetManager;

        public GL_Form()
        {
            connectForm = new ConnectForm();
            connectForm.connectEvent += new ConnectForm.Connecting(connectForm_connectEvent);
            
            InitializeComponent();
            connectForm.Show(this);
        }

        void connectForm_connectEvent(object sender, EventArgs e)
        {
            address = "tcp://" + connectForm.GetText() + ":8007/";
            InitializeGraphics();
        }

        private void InitializeGraphics()
        {
            openGLAssetManager = new AssetManagerGL();
            glPanel.ResourceManager = openGLAssetManager;

            AppSettingsReader appSettingReader = new AppSettingsReader();
            try
            {
                assetManager = (AssetManager)Activator.GetObject(typeof(AssetManager), address + "Asset Manager");

                viewProxy = (ViewProxy)assetManager.Find(typeof(ViewProxy), "Main View");
                viewHandler = new ViewHandler(viewProxy);
                camera = (ICamera)assetManager.Find(typeof(ICamera), "PerspectiveView");
            }
            catch
            {
                DialogResult dr = MessageBox.Show("Could not connect to remote machine. Closing.",
                    "Error", MessageBoxButtons.OK);
                if (dr == DialogResult.OK)
                {
                    Application.Exit();
                }
            }

            //(un)comment if you want to (en/dis)able local camera mouse control in this window
            examiner = new ExaminerMouseHandler();
            examiner.OwnerControl = glPanel;
            examiner.AddSlave(camera as ITransform);
            examiner.AddSlave(camera as IZoomLens);
            
            //any change in assets, like changing transfer function, etc. should be visible
            //immediately in our window, thus we should subscribe to the chanded events of
            //every asset
            //List<IAssetManaged> assets = AssetManager.Instance.FindAll(typeof(IAssetManaged));
            List<IAssetManaged> assets = assetManager.FindAll(typeof(IAssetManaged));
            eventHandler = new IAssetManagedHandler(invalidateEvent);
            foreach (IAssetManaged asset in assets)
            {
                asset.AddChangedEventHandler(eventHandler);
            }            

            this.Resize += new System.EventHandler(this.OpenGLForm_Resize);
            this.Validated += new System.EventHandler(this.OpenGLForm_Resize);
            glPanel.renderScene += new RenderScene(viewHandler.CompositeLayers);
        }

        protected void OpenGLForm_Resize(object sender, System.EventArgs e)
        {
            if (this.viewProxy != null && this.camera != null)
            {
                //hack! for some reason, this method is called when the window is minimized,
                //which causes the viewport to change to zero size and thus in main window 
                //everything disappears
                if (glPanel.Width == 0 || glPanel.Height == 0)
                {
                    return;
                }

                Vector2i newVector = new Vector2i(glPanel.Width, glPanel.Height);
                viewProxy.Viewport = new Viewport(new Vector2i(0, 0), newVector);

                float aspect = (float)glPanel.Width / (float)glPanel.Height;
                this.camera.AspectRatio = aspect;
                glPanel.Invalidate();
            }
        }

        //should be public so that it can be accessed via .net remoting
        //otherwise we'll get RemotingException
        public void invalidateEvent(IAssetManaged obj)
        {
            this.glPanel.Invalidate();
        }

        protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            base.OnClosing(e);

            try
            {
                List<IAssetManaged> assets = assetManager.FindAll(typeof(IAssetManaged));
                foreach (IAssetManaged asset in assets)
                {
                    asset.RemoveChangedEventHandler(eventHandler);
                }

                //remove all change handlers from the proxies - if this is not done,
                //main window will keep freezing while receiving remoting exceptions
                openGLAssetManager.Dispose();

                //have to do this manually, because 
                //viewHandler is not in openGLAssetManager
                viewHandler.Dispose();
            }
            catch { }
        }
    }
}
